package cn.mldn.homework.reflection;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 反射得到Person源代码有如下步骤 
 * 1.获得包名 
 * 2.获得类名 
 * 3.获得构造方法 
 * 4.获得属性 
 * 5.获得方法 
 * 6.组装成为一个类
 */
public class GeneratePerson
{
	private static final String BLANK = " ";
	private static final String TAB = "\t";
	private StringBuilder sb = new StringBuilder();
	
	private static Class<?> clazz = null;

	public static void main(String[] args)
	{
		GeneratePerson gp = new GeneratePerson();
		gp.generate();
	}
	
	static
	{
		try
		{
			clazz = Class.forName("cn.mldn.homework.reflection.Person");
		} catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}
	}

	public void generate()
	{
		this.getPackageDesc();
		this.getClassDesc();
		this.getFieldDesc();
		this.getConstructorDesc();
		this.getMethodDesc();
		sb.append("\n}");
		this.generateOutput();
		
		System.out.println("Java代码生成成功！");
	}

	private void getPackageDesc()
	{
		String packageName = clazz.getPackage().getName();
		sb.append("package " + packageName + ".generated;");
	}

	/**
	 * Modifier类修饰符的对应情况
	 * Modifier.PUBLIC //1
	 * Modifier.PRIVATE//2
	 * Modifier.PROTECTED//4
	 * "default"//0
	 * modifier值>=512即为interface，0-511是class
	 */
	private void getClassDesc()
	{
		String classModifier = "";
		int modifier = clazz.getModifiers();
		if (modifier == 0)
		{
			classModifier = "class";
		} else if (modifier == 1)
		{
			classModifier = "public class";
		} else
		{
			if (Modifier.isPublic(modifier))
			{
				classModifier = "public interface";
			} else
			{
				classModifier = "interface";
			}
		}
		
		String className = clazz.getSimpleName();
		
		sb.append("\n\n" + classModifier + BLANK + className + "{");
	}

	private void getConstructorDesc()
	{
		Constructor[] cons = clazz.getDeclaredConstructors();
		
		for (Constructor c : cons)
		{
			Class[] param = c.getParameterTypes();
			StringBuilder paramSB = new StringBuilder();
			
			// 有参数的方法，要在类型后面添加变量名
			if (param.length > 0)
			{
				paramSB.append(clazz.getSimpleName() + "(");
				
				String arg = "arg";
				
				for (int i = 0; i < param.length; i++)
				{
					paramSB.append(param[i].getCanonicalName() + BLANK + arg + i + ",");
				}
				
				paramSB = new StringBuilder(paramSB.substring(0, paramSB.length() - 1));
				paramSB.append(")");
				
				String name = c.toString();
				name = name.replaceFirst("\\S(\\w*\\.*)*\\((\\w*\\.*\\ *)*\\)", paramSB.toString());
				
				sb.append("\n" + TAB + name + "{\n\n" + TAB + "}\n");
				continue;
			}

			String name = c.toString();
			name = name.replaceFirst("\\S(\\w*\\.*)*\\(", clazz.getSimpleName() + "(");
			
			sb.append("\n" + TAB + name + "{\n\n" + TAB + "}\n");
		}
	}

	private void getFieldDesc()
	{
		Field[] field = clazz.getDeclaredFields();
		
		for (Field f : field)
		{
			String name = f.toString();
			name = name.replaceFirst("\\S(\\w*\\.*)*$", f.getName());
			
			sb.append("\n" + TAB + name + ";");
		}
		
		sb.append("\n");
	}

	private void getMethodDesc()
	{
		Method[] method = clazz.getDeclaredMethods();
		
		for (Method m : method)
		{
			Class[] param = m.getParameterTypes();
			StringBuilder paramSB = new StringBuilder();
			
			// 有参数的方法，要在类型后面添加变量名
			if (param.length > 0)
			{
				paramSB.append(m.getName() + "(");
				
				String arg = "arg";
				
				for (int i = 0; i < param.length; i++)
				{
					paramSB.append(param[i].getCanonicalName() + BLANK + arg + i + ",");
				}
				
				paramSB = new StringBuilder(paramSB.substring(0, paramSB.length() - 1));
				paramSB.append(")");
				
				String name = m.toString();
				name = name.replaceFirst("\\S(\\w*\\.*)*\\((\\w*\\.*\\ *)*\\)", paramSB.toString());
				
				sb.append("\n" + TAB + name + "{\n\n" + TAB + "}\n");
				continue;
			}

			String name = m.toString();
			name = name.replaceFirst("\\S(\\w*\\.*)*\\(", m.getName() + "(");
			
			// 获得return语句
			String attrName = StringUtil.firstCharToLower(m.getName().substring(3));
			paramSB.append("\n" + TAB + TAB + "return " + attrName + ";");

			sb.append("\n" + TAB + name + "{");
			sb.append(paramSB.toString() + "\n" + TAB + "}\n");
		}
	}

	private void generateOutput()
	{
		String path = clazz.getPackage().getName();
		path = path.replace(".", "\\");
		
		String url = System.getProperty("user.dir") + "\\src\\" + path + "\\generated\\" + clazz.getSimpleName()
				+ ".java";
		
		FileOutputStream fileWriter;
		try
		{
			fileWriter = new FileOutputStream(url);
			fileWriter.write(sb.toString().getBytes("UTF-8"));
			
			fileWriter.flush();
			fileWriter.close();
		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		} catch (UnsupportedEncodingException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}
